package com.lzp.java.concurrent.flowcontrol.condition;

import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author lzp
 * @Description: 使用Condition实现生产者消费者
 * @date 2021/3/6
 */
public class ProducerConsumerByCondition {
    private int capacity = 10;
    private Queue queue = new PriorityQueue(capacity);
    private Lock lock = new ReentrantLock();
    private Condition notFull = lock.newCondition();
    private Condition notEmpty = lock.newCondition();

    class Producer implements Runnable {

        @Override
        public void run() {
            while (true) {
                lock.lock();
                try {
                    while (queue.size() == capacity) {
                        try {
                            System.out.println("队列满，等待消费");
                            notFull.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    queue.offer(1);
                    notEmpty.signalAll();
                    System.out.println("生产完一个元素，队列容量:" + queue.size());
                } finally {
                    lock.unlock();
                }
            }
        }
    }
    class Consumer implements Runnable {

        @Override
        public void run() {
            while (true) {
                lock.lock();
                try {
                    while (queue.size() == 0) {
                        System.out.println("队列空，等待生产元素");
                        notEmpty.await();
                    }
                    TimeUnit.MILLISECONDS.sleep((long) (Math.random() * 1000));
                    queue.poll();
                    notFull.signalAll();
                    System.out.println("消费一个元素，队列容量：" + queue.size());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        }
    }

    public static void main(String[] args) {
        ProducerConsumerByCondition demo = new ProducerConsumerByCondition();
        Thread producer = new Thread(demo.new Producer());
        Thread consumer = new Thread(demo.new Consumer());
        producer.start();
        consumer.start();
    }
}
